package model.arboles;
/*

    This file is part of Logica-Logike.

    Logica-Logike is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation version 3 of the License.

    Logica-Logike is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Logica-Logike.  If not, see <http://www.gnu.org/licenses/>.

 */
/**
 * @author Maria Julia Racca;
 */
public class LogicalLaws {

    public static Proposition leyDeMorgan(Proposition prop) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;
        Operation centralOperation = p.getOperation();

        if (!centralOperation.equals(Operation.OR)
                && !centralOperation.equals(Operation.AND)) {
            System.err.println("No se puede aplicar morgan");
            return p;
            // o tirar excepcion!!
        }

        Proposition first = p.getFirst();
        first.setNegation(true);

        Proposition second = p.getSecond();
        second.setNegation(true);

        if (centralOperation.equals(Operation.AND)) {
            p.setOperation(Operation.OR);
        } else {
            p.setOperation(Operation.AND);
        }

        p.setNegation(true);
        return p;

    }

    public static Proposition propiedadConmutativa(Proposition prop) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;

        if (p.getOperation().equals(Operation.ENTONCES)) {
            System.err.println("No se puede aplicar la conmutativa!");
            return p;
            // o tirar excepcion!!
        }
        Proposition first = p.getFirst();
        p.setFirst(p.getSecond());
        p.setSecond(first);

        return p;
    }

    public static Proposition definicionCondicional(Proposition prop) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;
        Operation o = p.getOperation();

        if (!o.equals(Operation.ENTONCES) && !o.equals(Operation.OR)
                && !o.equals(Operation.AND)) {

            System.err.println("No se puede aplicar la def. conficional!");
            return p;
            // o tirar excepcion!!
        }

        if (o.equals(Operation.AND)) {
            p = (MolecularProposition) leyDeMorgan(p);
        }

        Proposition first = p.getFirst();
        first.setNegation(true);

        if (o.equals(Operation.ENTONCES)) {
            p.setOperation(Operation.OR);
        } else {
            p.setOperation(Operation.ENTONCES);
        }

        return p;
        // Si transformo A=>B me devuelve -A|B, no lo equivalente en morgan!
    }

    public static Proposition definicionBicondicional(Proposition prop) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;
        if (!p.getOperation().equals(Operation.SIYSOLOSI)) {
            System.err.println("No se puede aplicar la def. biconficional!");
            return p;
            // o tirar excepcion!!
        }

        Proposition f = p.getFirst();
        Proposition s = p.getSecond();

        MolecularProposition first = new MolecularProposition(f,
                Operation.ENTONCES, s, false);
        MolecularProposition second = new MolecularProposition(s,
                Operation.ENTONCES, f, false);

        return new MolecularProposition(first, Operation.AND, second, p
                .getNegated());

        // Solo el camino de ida! de A<=>B devuelvo (A=>B).(B=>A)
    }

    public static Proposition deNegacion(Proposition prop) {

        // No se puede hacer con la estrucutra que elegi porque no soporta doble
        // negacion. Igualmente cuando le pido negar una proposicion y esta ya
        // estbaa negada uso la ley de negacion en la logica

        return prop;
    }

    public static Proposition propiedadAsociativa(Proposition prop) {
        return propiedadDistributivaAsociativa(prop, false);
    }

    public static Proposition transposicion(Proposition prop) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;
        Operation o = p.getOperation();

        if (!o.equals(Operation.ENTONCES)) {
            System.err.println("No se puede aplicar la transposicion");
            return p;
        }

        Proposition first = p.getFirst();
        Proposition second = p.getSecond();

        first.setNegation(true);
        second.setNegation(true);

        p.setFirst(second);
        p.setSecond(first);

        return p;
    }

    public static Proposition propiedadDistributiva(Proposition prop) {
        return propiedadDistributivaAsociativa(prop, true);
    }

    private static Proposition propiedadDistributivaAsociativa(Proposition prop,
                                                               boolean b) {

        if (prop instanceof AtomicProposition) {
            return prop;
        }

        MolecularProposition p = (MolecularProposition) prop;
        Operation o = p.getOperation();

        if (!o.equals(Operation.OR) && !o.equals(Operation.AND)) {
            System.err.println("No se puede aplicar la prop distributiva");
            return p;
            // o tirar excepcion!!
        }

        Proposition first = p.getFirst();
        Proposition second = p.getSecond();

        MolecularProposition molecular = null;
        Proposition proposition;

        if (first instanceof AtomicProposition) {
            if (second instanceof AtomicProposition) {
                return p;
            }
            molecular = (MolecularProposition) second;
            proposition = first;
        } else {

            molecular = (MolecularProposition) first;
            proposition = second;
        }

        if (molecular.getOperation().equals(Operation.ENTONCES)) {
            molecular = (MolecularProposition) definicionCondicional(molecular);

        } else if (molecular.getOperation().equals(Operation.SIYSOLOSI)) {
            molecular = (MolecularProposition) definicionBicondicional(molecular);
        }

        if (molecular.getNegated().equals(Operation.NOT)) {
            molecular = (MolecularProposition) leyDeMorgan(molecular);
        }

        if (b) {
            return distribuir(p, molecular, proposition);
        }
        return asociar(p, molecular, proposition);

    }

    private static Proposition asociar(MolecularProposition p,
                                       MolecularProposition molecular, Proposition proposition) {

        Operation o = p.getOperation();

        if (!molecular.getOperation().equals(o)) {
            System.err.println("No se puede aplicar la prop. asociativa");
            return p;
        }

        MolecularProposition aux = new MolecularProposition(molecular
                .getSecond(), o, proposition, false);
        return new MolecularProposition(molecular.getFirst(), o, aux, p
                .getNegated());

    }

    private static Proposition distribuir(MolecularProposition p,
                                          MolecularProposition molecular, Proposition proposition) {
        return proposition;

    }

}
